package sharing

import activiti.CommonTask
import grails.util.Environment
import groovy.time.TimeCategory
import org.apache.commons.lang.StringUtils
import org.apache.poi.hssf.usermodel.*
import org.apache.poi.hssf.util.HSSFColor
import org.apache.poi.ss.usermodel.*
import org.apache.poi.ss.util.CellRangeAddress
import org.apache.poi.xssf.usermodel.XSSFCell
import org.apache.poi.xssf.usermodel.XSSFRow
import org.apache.poi.xssf.usermodel.XSSFSheet
import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
import org.codehaus.groovy.grails.web.json.JSONArray
import org.codehaus.groovy.grails.web.json.JSONObject
import org.codehaus.groovy.grails.web.util.WebUtils
import system.Department
import system.StaffMember

import java.text.SimpleDateFormat

class UtilsService {

    static transactional = true
    public static ROOT_PATH

    public static plugControlListMap=[:];
//    public  static SYSURL='http://localhost:8010/prm/openInvoke/invoke'//接口
    public static String dateFmt = "yyyy-MM-dd HH:mm:ss.SSS"
    public static SimpleDateFormat dateformat = new SimpleDateFormat(dateFmt)
    static ArrayList truncArr = ['metaClass', 'log', 'properties', 'workstatus', 'workstatusList', 'attached', 'class', 'constraints', 'version', 'dirtyPropertyNames', 'metaClass', 'errors', 'dirty']
    def containlist = ['java.lang.String', 'java.lang.Float', 'java.lang.Character', 'java.lang.Long', 'java.lang.Double', 'java.lang.Integer', 'java.lang.Short', 'java.lang.Byte', 'java.sql.Timestamp', null, 'java.sql.Timestamp', 'java.lang.Boolean']
    def historyService

    //转换yyyy-MM-dd字符串为日期类型
    Date getStrDate(String datestr) {
        dateformat.parse(datestr + ' 00:00:00.000')
    }

    Date getStrDateMax(String datestr) {
        dateformat.parse(datestr + ' 23:59:59.999')
    }
    //在多条记录间分配数量all，返回各条记录分配的实际值
    def allocquan(String keyfld, String quanfld, List arr, BigDecimal all, List actarr, closure) {
        def rst = [:]
        def actual = new BigDecimal(0)
        arr.find {
            if (actual >= all)
                return true
            def quan = it."$quanfld"
            if (quan < all - actual) {
                rst.put(it."$keyfld", quan)
                actual += quan
                closure it, quan
            } else {
                rst.put(it."$keyfld", new BigDecimal(all - actual))
                closure it, new BigDecimal(all - actual)
                actual = all
            }

            false
        }
        actarr << actual
        rst
    }

    //删除 多条记录  params.ids 存放删除 的id    className 是实体   delstatus 可以删除的状态   statusAttar 状态属性 ,showstatusAttar 显示用的状态属性  name 实体的描述名称
    def deleteMany(params, Class className, List delstatus, name, statusAttar = 'status', showstatusAttar = 'status') {
        int right = 0, error = 0;
        String errorMsg = "失败原因:"
        def list = [], result = [success: true];
        if (params.ids?.getClass()?.getName() == "[Ljava.lang.String") { //防止一个id时被拆分
            params.ids.each {
                list << it
            }
        } else list << params.ids
        log.debug(list?.flatten())
        list?.flatten()?.each {
            if (!it) return
            long id = (it.toString().trim() as long)
            def Instance = className.get(id)
            if (Instance) {
                try {
                    if (delstatus == null || delstatus.contains(Instance."${statusAttar}")) {
                        Instance.delete(flush: params.flush?:true)
                        right++;
                        log.info("删除${name}" + id + "成功")
                    } else {
                        error++
                        errorMsg += "${name}" + id + "状态是 " + Instance."${showstatusAttar}" + "; "
                        log.info("删除${name}" + id + "失败." + " 原因:${name}" + id + "状态/类型是 " + Instance."${showstatusAttar}")
                    }
                }
                catch (org.springframework.dao.DataIntegrityViolationException e) {
                    e.printStackTrace()

                    log.error("删除${name}" + id + "失败 原因 已与其它单据关联，无法删除")
                    errorMsg += "已与其它单据关联;"
                    error++
                }
            } else {
                log.info("${name}" + id + "不存在,删除失败")
                errorMsg += "${name}" + id + "不存在,"
                error++
            }
        }
        if (error > 0) {
            result << [message: "成功删除${right}个,失败${error}个,${errorMsg}"]
        }else{
            result << [message: "成功删除${right}个"]
        }
        result
    }


    def getQjqj(String qj) {
        def rst = []

        def str = qj[0..3] + '-' + qj[4..5] + '-25'
        def end = getStrDate(str)
        def cal = Calendar.getInstance()
        cal.setTime(end)
        cal.add(Calendar.MONTH, -1)
        rst << cal.getTime()
        rst << end
        rst
    }

    def getUploadPath(def servletcontext) {
        def path = servletcontext.getRealPath("/upload/test")
        def rst = path[0..path.length() - 5]

        def env = Environment.getCurrent()
        if (env.toString() != 'DEVELOPMENT') {
            int i = rst.lastIndexOf(servletcontext.getContextPath()[1..servletcontext.getContextPath().length() - 1])
            rst = rst[0..i - 2] + rst[i + servletcontext.getContextPath().length() - 1..rst.length() - 1]
            def file = new File(rst[0..rst.length() - 2])
            if (!file.exists()) {
                file.mkdir()
            }
        }
        rst
    }

    def copyFile(srcPath, desPath) {
        log.debug "${srcPath},${desPath}"
        File src = new File(srcPath);
        File des = new File(desPath);

        def length = 1024;
        def fin = new FileInputStream(src);
        def fout = new FileOutputStream(des);
        byte[] buffer = new byte[length];
        while (true) {
            def ins = fin.read(buffer);
            if (ins == -1) {
                fin.close();
                fout.flush();
                fout.close();
                break;
            } else
                fout.write(buffer, 0, ins);
        }
    }


    def getUploadExcelPath(def servletcontext) {
        def path = servletcontext.getRealPath("/test")
        path = path[0..path.length() - 5]
        if (path.endsWith("\\")) path = path[0..path.length() - 2]

        path = (path[0..path.lastIndexOf("\\")]) + "ribao\\"

    }

    //fang add 2012-4-16 删除 指定属性 sth
    def removeSth(nodesMap, String sth) {
        if (nodesMap == null) return
        if (nodesMap.size() > 0)
            nodesMap.each { id, node ->
                node.remove(sth)
                removeSth(node.children, sth)
            }
        else {
            nodesMap.remove(sth)
            removeSth(nodesMap.children, sth)
        }
        nodesMap
    }

    def removeSth(nodesMap, List sth) {
        log.debug("list-->" + nodesMap)
        if (nodesMap == null || nodesMap.size() == 0) return

        log.debug(nodesMap[0])
        if (nodesMap[0])
            nodesMap.each { node ->
                sth.each { itt ->
                    node.remove(itt.toString())

                }
                removeSth(node.children, sth)
            }
        else {
            sth.each { itt ->
                nodesMap.remove(itt)
                removeSth(nodesMap.children, sth)
            }
        }
        nodesMap
    }

    def buildDomainList(list, clo) {
        def rds = []
        list?.each {
            def b = [:] + it.properties

            b = truncProp(it, b) { amap ->
                amap << ['id': it.id]
                clo(amap, it)
            }
            rds << b
        }
        return rds
    }

    def truncProp(instance, pmap, param = null, closure) {   //delarray 是否删除数组     true 是 删除
        if (!param) param = [:]
        if (param.delarray == null) param.delarray = true
        if (param.precision == null) param.precision = 2
        if (param.allowformat == null) param.allowformat = false//默认 不对日期转为字符串
//        if (param.allowprecision == null) param.allowprecision = true//默认 控制数字的精度
        if (param.format == null) param.format = "yyyy-MM-dd"
        truncArr.each { itt ->
            pmap.remove(itt)    //fang        update
        }
        def two = [:]
        def temlist = getHasmanyProperties(instance.class).name
        temlist.addAll(getClassPersistentProperties(instance.class).name)
        pmap.each { k, v ->
//            log.debug(param.delarray.toString() + "   " + k + "--> " + v + "  " + v?.class?.name)
            if (v == null) v = ""
            if (k?.toString()?.endsWith('Service')) { //去掉 Service
                two.remove(k)
            } else if (param.delarray && (v?.class?.name in ['java.util.ArrayList', 'org.hibernate.collection.PersistentSet', 'java.util.HashSet'])) {
                //据条件去除数组
                two.remove(k)
            } else if (v?.class?.name in ['java.lang.Double ', 'java.lang.Float', 'java.math.BigDecimal']) { //控制精度
                if (param.allowprecision)
                    two.put(k, (v as BigDecimal).setScale(param.precision, BigDecimal.ROUND_HALF_UP))
                else {
                    two.put(k, v)
                }
            } else if (param.allowformat && v?.class?.name in ['java.util.Date', 'java.sql.Timestamp']) {
                two.put(k, v?.format(param.format))
            } else if (temlist?.contains(k)) {
                def id = 0, name = ''
                if (validString(v)) {
                    id = v.id; name = v.toString()
                }
                two.put(k, id)
                two.put(k + 'Id', id)
                two.put((k + "Name"), name)
            } else if (!containlist.contains(v?.class?.name)) {
//                two.put(k, v?.toString())
//                log.debug(param.delarray.toString() + "   " + k + "--> " + v?.class?.name)
                two.put(k, v?.toString())
            } else
                two.put(k, v)
        }

        closure two
        two
    }

    /**
     * @param out
     * @param titles
     *
     * @param datas
     * @return
     */
    def expExcel(out, titles, datas, clo) {
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet("new sheet");
        HSSFRow row
        HSSFCell cell
        HSSFCellStyle style = wb.createCellStyle()
        HSSFFont font = wb.createFont()
        font.setFontHeightInPoints((short) 12)
        //font.setFontName("宋体")
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD)
        style.setFont(font)
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER)
        //style.setFillBackgroundColor(HSSFColor.ORANGE.index)
        //        style.setFillPattern(HSSFCellStyle.)
        // set the title
        row = sheet.createRow((short) 0);
        titles.eachWithIndex { title, i ->
            cell = row.createCell((short) (i));
            cell.setCellStyle(style)
            cell.setCellValue(title);
        }
        datas.eachWithIndex { data, i ->
            row = sheet.createRow((short) (i + 1));
            def data1 = clo(data)
            titles.eachWithIndex { p, j ->
                row.createCell((short) (j)).setCellValue(data1."${p}".toString());

            }

        }

        // Write the output to a file
        wb.write(out);
        out.close()
    }

    /**
     * 获得某个类的关联类型(实体)的属性的map的列表 <br>
     * @param c 类  比如Staffmember
     * @return [name=checker,type=class system.StaffMember,persistent=true,optional=true,association=true,bidirectional=false,association-type=one-to-one],
     * .name为 属性名称的列表  .type 为对应类型名称的列表      association为是否为关联类型
     */
    def getClassPersistentProperties(c) {
        def cps = new DefaultGrailsDomainClass(c).getPersistentProperties().toList().findAll {
            it.isAssociation()
        }
        cps
    }
    /**
     *      得到非实体属性
     * @param c 类  比如Staffmember
     * @return [name=amount,type=class java.math.BigDecimal,persistent=true,optional=false,association=false,bidirectional=false,association-type=],
     */
    def getClassUnPersistentProperties(c) {
        def cps = new DefaultGrailsDomainClass(c).getPersistentProperties().toList().findAll {
            !it.isAssociation()
        }
        cps
    }
    /**      得到hasMany属性
     * [name=paymentAppBuy,type=interface java.util.Set,persistent=true,optional=true,association=true,bidirectional=true,association-type=one-to-many],
     */
    def getHasmanyProperties(c) {
        getClassPersistentProperties(c).findAll { it.oneToMany }
    }
    /**      得到HasOne属性
     * [name=paymentAppBuy,type=interface java.util.Set,persistent=true,optional=true,association=true,bidirectional=true,association-type=one-to-many],
     */
    def getHasOneProperties(c) {
        getClassPersistentProperties(c).findAll { it.oneToOne }
    } /**      得到many-to-one属性     ,例如parent
     * [name=parent,type=class system.Dict,persistent=true,optional=true,association=true,bidirectional=true,association-type=many-to-one]
     */
    def getManyToOneProperties(c) {
        getClassPersistentProperties(c).findAll { it.isManyToOne() }
    }
    /**
     * 判断字符串是否是整数
     */
    public boolean isInteger(String value) {
        try {
            Long.parseLong(value);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 判断字符串是否是浮点数
     */
    public boolean isDouble(String value) {
        try {
            Double.parseDouble(value);
            if (value.contains("."))
                return true;
            return false;
        } catch (NumberFormatException e) {
            return false;
        }
    }
    /**
     * 判断字符串是否是浮点数
     */
    public boolean isBigDecimal(String value) {
        try {
            new BigDecimal(value)
        } catch (NumberFormatException e) {
            return false;
        }
        return true
    }
    /**
     * 判断字符串是否是数字
     */
    public boolean isNumber(value) {
        if (value == null || value?.toString() == "") return false
        else
            return isInteger(value?.toString()) || isDouble(value?.toString())||isBigDecimal(value?.toString());
    }

    // 得到后 i 个月
    Date getAfterMonth(Date jzdate, int i) {
        def day1 = jzdate
        def newday = null
        use(TimeCategory) {
            newday = (day1 + i.months)
        }
        newday
    }
    // 得到前 i 个月
    Date getBeforeMonth(Date jzdate, int i) {
        def day1 = jzdate
        def newday = null
        use(TimeCategory) {
            newday = (day1 - i.months)
        }
        newday
    }

    public Date getFirstDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        //得到月初
        calendar.setTime(date)
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
        def dateStr = calendar.getTime().format('yyyy-MM-dd')
        dateStr += "00:00:00"
        new SimpleDateFormat("yyyy-MM-ddHH:mm:ss").parse(dateStr)
    }

    public Date getLastDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date)
        //得到月末
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        def dateStr = calendar.getTime().format('yyyy-MM-dd')
        dateStr += "23:59:59"
        new SimpleDateFormat("yyyy-MM-ddHH:mm:ss").parse(dateStr)
//        return calendar.getTime();
    }
    //得到年初
    public Date getFirstDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance()
        calendar.setTime(date)
        calendar.set(Calendar.DAY_OF_YEAR, calendar.getActualMinimum(Calendar.DAY_OF_YEAR))
        def dateStr = calendar.getTime().format('yyyy-MM-dd')
        dateStr += "00:00:00"
        new SimpleDateFormat("yyyy-MM-ddHH:mm:ss").parse(dateStr)
    }

    public Date getDayStart(Date date) {
        def dateStr = date.format('yyyy-MM-dd')
        dateStr += "00:00:00"
        new SimpleDateFormat("yyyy-MM-ddHH:mm:ss").parse(dateStr)
    }

    public Date getDayEnd(Date date) {
        def dateStr = date.format('yyyy-MM-dd')
        dateStr += "23:59:59"
        new SimpleDateFormat("yyyy-MM-ddHH:mm:ss").parse(dateStr)
//        return calendar.getTime();
    }

    public int getDaysOfMonth(Date date) {
        return getLastDay(date) - getFirstDay(date) + 1
    }

    public int getDaysToEnd(Date date) {
        def endDay = getLastDay(date)
        endDay - date + 1
    }

    public boolean IsFirstDayOfMonth(Date date) {
        def firstDay = getFirstDay(date)
        if (firstDay - date == 0)
            return true
        else
            return false
    }


    def getYue(date, int year = 2000, int month = 1) {
        def arr = []
        if (date) {
            def cal = Calendar.getInstance(Locale.CHINA)
            cal.setTime(date)
            def tmp = Calendar.getInstance(Locale.CHINA)
            tmp.clear()
            tmp.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 1)
            arr << tmp.getTime()
            def c = tmp.clone()
            c.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.getActualMaximum(Calendar.DAY_OF_MONTH))
            c.add(Calendar.DAY_OF_MONTH, 1)
            arr << c.getTime()
        } else {
            def tmp = Calendar.getInstance()
            tmp.set(year, month - 1, 1)
            return getYue(tmp.getTime())
        }

        arr
    }

    def getRequest() {
        def webUtils = WebUtils.retrieveGrailsWebRequest()
        webUtils.getCurrentRequest()
    }

//Getting the Response object

    def getResponse() {
        def webUtils = WebUtils.retrieveGrailsWebRequest()
        webUtils.getCurrentResponse()
    }

//Getting the ServletContext object

    def getServletContext() {
        def webUtils = WebUtils.retrieveGrailsWebRequest()
        webUtils.getServletContext()
    }

//Getting the Session object

    def getSession() {
        def webUtils = WebUtils.retrieveGrailsWebRequest()
        webUtils.getCurrentRequest().getSession()
    }

    def getCurrentDate() {
        session.currentDate ?: new Date()
    }

    //输入字符串 自适应 转为 日期
    def strToDate(String date) {
        if (date) {
            def result
            if (date.contains('T')) {
                try {
                    result = Date.parse("yyyy-MM-dd'T'HH:mm:ss", date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) try {
                    result = Date.parse("yyyy-MM-dd'T'HH:mm", date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) try {
                    result = Date.parse("yyyy-MM-dd'T'HH", date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) try {
                    result = Date.parse("yyyy-MM-dd'T'", date)
                } catch (Exception e) {
                    result = null
                }
            } else if (!date.contains('-')&&date.contains(":")) {
                if (!result) try {
                    result = Date.parse('yyyyMMdd HH:mm:ss', date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) try {
                    result = Date.parse('yyyyMMdd HH:mm', date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) try {
                    result = Date.parse('yyyyMMdd HH', date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) try {
                    result = Date.parse('yyyyMMdd', date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) {
                    try {
                        result = Date.parse("yyyy", date)
                    } catch (Exception e) {
                        result = null
                    }
                }
            }else if (!date.contains('-')&&!date.contains(":")) {
                if (!result) try {
                    result = Date.parse('yyyyMMdd HHmmss', date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) try {
                    result = Date.parse('yyyyMMdd HHmm', date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) try {
                    result = Date.parse('yyyyMMdd', date)
                } catch (Exception e) {
                    result = null
                }
                if (!result) {
                    try {
                        result = Date.parse("yyyy", date)
                    } catch (Exception e) {
                        result = null
                    }
                }
            }
            else {
                if (!result) {
                    try {
                        result = Date.parse('yyyy-MM-dd HH:mm:ss', date)
                    } catch (Exception e) {
                        result = null
                    }
                }
                if (!result) {
                    try {
                        result = Date.parse('yyyy-MM-dd HH:mm', date)
                    } catch (Exception e) {
                        result = null
                    }
                }
                if (!result) {
                    try {
                        result = Date.parse('yyyy-MM-dd HH', date)
                    } catch (Exception e) {
                        result = null
                    }
                }
                if (!result) {
                    try {
                        result = Date.parse('yyyy-MM-dd', date)
                    } catch (Exception e) {
                        result = null
                    }
                }
                if (!result) {
                    try {
                        result = Date.parse('yyyy-MM', date)
                    } catch (Exception e) {
                        result = null
                    }
                }
            }

            result
        }
    }


    def validString(value) {
        if (value != null && value?.toString()?.trim() != "" && value?.toString() != "null" && value != "undefined" && value != [] && value != "[]") return true
        else return false
    }

    //写Excel 常用方法 fang add
    private Map<String, CellStyle> createStyles(Workbook wb) {
        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
        DataFormat df = wb.createDataFormat();
        //表头 样式
        CellStyle style;
        Font headerFont = wb.createFont();
        headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
        headerFont.setFontHeightInPoints((short) 16);
        style = wb.createCellStyle();//不带边框
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
        //  style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        style.setFont(headerFont);
        styles.put("header", style);
        //第二行 不带边框的样式
        Font twoFont = wb.createFont();
        twoFont.setFontHeightInPoints((short) 10.5);
        style = wb.createCellStyle();//不带边框;
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        style.setFont(twoFont);
        style.setWrapText(true);
        styles.put("twoRow", style);

        //正文标题 加粗 样式
        Font littleHeader = wb.createFont();
        littleHeader.setFontHeightInPoints((short) 11);
        littleHeader.setBoldweight(Font.BOLDWEIGHT_BOLD);
        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        style.setFont(littleHeader);
        style.setBorderTop((short) 1);//边框
        style.setBorderLeft((short) 1);
        style.setBorderRight((short) 1);
        style.setWrapText(true);
        styles.put("littleHeader", style);

        //正文样式
        Font bodyFont = wb.createFont();
        bodyFont.setFontHeightInPoints((short) 10);
        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(CellStyle.ALIGN_CENTER);
        style.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        style.setFont(bodyFont);
        style.setWrapText(true);
        //style.setColumnWidth()
        styles.put("body", style);
        //redmin 1602 changfenghua 20140724 add start
        //正文样式加黄色背景
        Font bodyhzFont = wb.createFont();
        bodyhzFont.setFontHeightInPoints((short) 10);
        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(CellStyle.ALIGN_CENTER);
        style.setFillForegroundColor(IndexedColors.ORANGE.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        style.setFont(bodyhzFont);
        style.setWrapText(true);
        style.setFillBackgroundColor(HSSFColor.ORANGE.index);
        styles.put("bodyhz", style);
        //redmin 1602 changfenghua 20140724 add end

        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        style.setFont(headerFont);
        style.setDataFormat(df.getFormat("d-mmm"));
        styles.put("header_date", style);

        Font font1 = wb.createFont();
        font1.setBoldweight(Font.BOLDWEIGHT_BOLD);
        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_LEFT);
        style.setFont(font1);
        styles.put("cell_b", style);

        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setFont(font1);
        styles.put("cell_b_centered", style);

        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_RIGHT);
        style.setFont(font1);
        style.setDataFormat(df.getFormat("d-mmm"));
        styles.put("cell_b_date", style);

        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_RIGHT);
        style.setFont(font1);
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        style.setDataFormat(df.getFormat("d-mmm"));
        styles.put("cell_g", style);

        Font font2 = wb.createFont();
        font2.setColor(IndexedColors.BLUE.getIndex());
        font2.setBoldweight(Font.BOLDWEIGHT_BOLD);
        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_LEFT);
        style.setFont(font2);
        styles.put("cell_bb", style);

        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_RIGHT);
        style.setFont(font1);
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        style.setDataFormat(df.getFormat("d-mmm"));
        styles.put("cell_bg", style);

        Font font3 = wb.createFont();
        font3.setFontHeightInPoints((short) 14);
        font3.setColor(IndexedColors.DARK_BLUE.getIndex());
        font3.setBoldweight(Font.BOLDWEIGHT_BOLD);
        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_LEFT);
        style.setFont(font3);
        style.setWrapText(true);
        styles.put("cell_h", style);

        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_LEFT);
        style.setWrapText(true);
        styles.put("cell_normal", style);

        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_CENTER);
        style.setWrapText(true);
        styles.put("cell_normal_centered", style);

        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_RIGHT);
//        style.setWrapText(true);
        style.setDataFormat(df.getFormat("yyyy-mm-dd"));
        styles.put("cell_normal_date", style);

        style = createBorderedStyle(wb);
        style.setAlignment(CellStyle.ALIGN_LEFT);
        style.setIndention((short) 1);
        style.setWrapText(true);
        styles.put("cell_indented", style);

        style = createBorderedStyle(wb);
        style.setFillForegroundColor(IndexedColors.BLUE.getIndex());
        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
        styles.put("cell_blue", style);

        return styles;
    }

    private CellStyle createBorderedStyle(Workbook wb) {
        CellStyle style = wb.createCellStyle();
        style.setBorderRight(CellStyle.BORDER_THIN);
        style.setRightBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderBottom(CellStyle.BORDER_THIN);
        style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderLeft(CellStyle.BORDER_THIN);
        style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderTop(CellStyle.BORDER_THIN);
        style.setTopBorderColor(IndexedColors.BLACK.getIndex());
        return style;
    }
    //在正文区连续增加n个单元格
    private void addColl(HSSFCell cell, HSSFRow row, Map<String, CellStyle> styles, int begin, int end) {
        for (int i = begin; i <= end; i++) {
            cell = row.createCell(i);
            cell.setCellStyle(styles.get("body"));
        }
    }
    //增加多个相同样式 相同内容的单元格
    private void addCollValue(HSSFCell cell, HSSFRow row, Map<String, CellStyle> styles, String styleName, int begin, int end, value) {

        for (int i = begin; i <= end; i++) {
            cell = row.createCell(i);
            if (isNumber(value) && value.class != String) {
                cell.setCellValue(value as BigDecimal);
                cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC)
            } else {
                cell.setCellValue(value);
            }
            if (styleName && styleName != '')
                cell.setCellStyle(styles.get(styleName));
        }
    }
    private void addCollValue07(XSSFCell cell, XSSFRow row, Map<String, CellStyle> styles, String styleName, int begin, int end, value) {

        for (int i = begin; i <= end; i++) {
            cell = row.createCell(i);
            if (isNumber(value) && value.class != String) {
                cell.setCellValue(value as BigDecimal);
                cell.setCellType(XSSFCell.CELL_TYPE_NUMERIC)
            } else {
                cell.setCellValue(value);
            }
            if (styleName && styleName != '')
                cell.setCellStyle(styles.get(styleName));
        }
    }
    //  beginColl 开始列下标,  end 终止列下标  rowBegin 开始行下标      rowEnd开始列下标
    def addCollValueAndMerage(HSSFCell cell, Map<String, CellStyle> styles, styleName, int begin, int end, value, int rowBegin, int rowEnd, HSSFSheet sheet, short height = 400) {
        for (int i = rowBegin; i <= rowEnd; i++) {
            def row = sheet.getRow(i);
            if (row == null) {
                row = sheet.createRow(i)
            }
            row.setHeight((short) Short.valueOf(height));
            addCollValue(cell, row, styles, styleName?.toString(), begin, end, value);   //新建个separment单元格
        }
        def cellRangeAddress = new CellRangeAddress(rowBegin, rowEnd, begin, end);  //合并  separment个单元格 成一个
        sheet.addMergedRegion(cellRangeAddress);
    }
    def addCollValueAndMerage07(XSSFCell cell, Map<String, CellStyle> styles, styleName, int begin, int end, value, int rowBegin, int rowEnd, XSSFSheet sheet, short height = 400) {
        for (int i = rowBegin; i <= rowEnd; i++) {
            def row = sheet.getRow(i);
            if (row == null) {
                row = sheet.createRow(i)
            }
            row.setHeight((short) Short.valueOf(height));
            addCollValue07(cell, row, styles, styleName?.toString(), begin, end, value);   //新建个separment单元格
        }
        def cellRangeAddress = new CellRangeAddress(rowBegin, rowEnd, begin, end);  //合并  separment个单元格 成一个
        sheet.addMergedRegion(cellRangeAddress);
    }
    //增加一个行，在行里添加多个相同样式 不同内容的单元格
    private void addCollDifValue(HSSFCell cell, int rowNum, Map<String, CellStyle> styles, String styleName, int begin, int end, List value, HSSFSheet sheet, short height = 500) {
        def row = sheet.getRow(rowNum);
        if (row == null) {
            row = sheet.createRow(rowNum)
        }
        row.setHeight((short) Short.valueOf(height));
        int j = 0
        for (int i = begin; i <= end; i++) {
            cell = row.createCell(i);
            cell.setCellValue(value[j]);
            cell.setCellStyle(styles.get(styleName));
            j = j + 1
        }
    }

    //只能得到本级的所有属性分类的集合
    def getProsOne(instance) {
        Class Instance = instance.class
        def result = [:]
        result.all = []
        result.string = []
        result.domain = getHasOneProperties(Instance).name
        result.domain.addAll(getManyToOneProperties(Instance).name)
        result.hasMany = getHasmanyProperties(Instance).name
        result.date = []
        result.double = []
        result.boolean = []
        result.long = []
        result.int = []
        result.float = []
        result.all.addAll(result.domain)
        result.all.addAll(result.hasMany)
        def list = getClassUnPersistentProperties(Instance)
        list.each {
            result.all << it.getAt('name')
            if (it.type.toString().contains('String')) result.string << it.getAt('name')
            if (it.type.toString().contains('Date')) result.date << it.getAt('name')
            if (it.type.toString().contains('BigDecimal')) result.double << it.getAt('name')
            if (it.type.toString().contains('boolean') || it.type.toString().contains('Boolean')) result.boolean << it.getAt('name')
            if (it.type.toString().contains('long') || it.type.toString().contains('Long')) result.long << it.getAt('name')
            if (it.type.toString().contains('int') || it.type.toString().contains('Integer')) result.int << it.getAt('name')
            if (it.type.toString().contains('float') || it.type.toString().contains('Float')) result.float << it.getAt('name')
        }
        result
    }
    /**
     * 扩展到4级
     * 举例:
     * utilsService.getPros(Department.newInstance(),[jici_used:4])
     * 返回:
     * ['all':['departmentType', 'parent', 'children', 'cbzxCode', 'code', 'createMethod', 'dr', 'name', 'remark', dateCreated.departmentType, lastUpdated.departmentType, name.departmentType, departmentType.parent, parent.parent, children.parent, cbzxCode.parent, code.parent, createMethod.parent, dr.parent, name.parent, remark.parent, departmentType.dateCreated.parent, departmentType.lastUpdated.parent, departmentType.name.parent, parent.departmentType.parent, parent.parent.parent, parent.children.parent, parent.cbzxCode.parent, parent.code.parent, parent.createMethod.parent, parent.dr.parent, parent.name.parent, parent.remark.parent], 'string':['cbzxCode', 'code', 'createMethod', 'dr', 'name', 'remark', name.departmentType, cbzxCode.parent, code.parent, createMethod.parent, dr.parent, name.parent, remark.parent, departmentType.name.parent, parent.cbzxCode.parent, parent.code.parent, parent.createMethod.parent, parent.dr.parent, parent.name.parent, parent.remark.parent], 'domain':['departmentType', 'parent', departmentType.parent, parent.parent, parent.departmentType.parent, parent.parent.parent, parent.departmentType.dateCreated.parent, parent.departmentType.lastUpdated.parent, parent.departmentType.name.parent, parent.departmentType.name.parent, parent.departmentType.dateCreated.parent, parent.departmentType.lastUpdated.parent, parent.parent.departmentType.parent, parent.parent.parent.parent, parent.parent.children.parent, parent.parent.cbzxCode.parent, parent.parent.code.parent, parent.parent.createMethod.parent, parent.parent.dr.parent, parent.parent.name.parent, parent.parent.remark.parent, parent.parent.cbzxCode.parent, parent.parent.code.parent, parent.parent.createMethod.parent, parent.parent.dr.parent, parent.parent.name.parent, parent.parent.remark.parent, parent.parent.departmentType.parent, parent.parent.parent.parent, parent.parent.children.parent], 'hasMany':['children', parent.children.parent, children.parent], 'date':[dateCreated.departmentType, lastUpdated.departmentType, departmentType.dateCreated.parent, departmentType.lastUpdated.parent], 'double':[], 'boolean':[], 'long':[], 'int':[], 'float':[]]
     */

    def getPros(instance, map) {
        Class Instance = instance.class
        def result = getProsOne(instance)
        def domainMap = [], addPro = []
        domainMap.addAll(result.domain)
        domainMap.removeAll(addPro)
        domainMap.each { p ->    // [job,creater,parent]
            //把clas 中的所有属性合并到  result
            addPro.add(p)
            def newclas = new DefaultGrailsDomainClass(Instance).getPropertyByName(p).referencedPropertyType  //Job
            def tem = getProsOne(newclas.newInstance())
            tem.each { k, v ->    //domain ,[creater,parent.....]
                def listtem = result.get(k)
                v.each { vv ->
                    def newName = "${p}.${vv}" //属变为 比如 job.name
                    listtem.add(newName)
                }
                if (map?.jici_used >= 3) { //
                    if (k == 'domain') { //对 doamin 再次级联的属性分析
                        v.each { vv ->     //creater
                            def newClas2 = new DefaultGrailsDomainClass(newclas).getPropertyByName(vv).referencedPropertyType //StaffMember
                            tem = getProsOne(newClas2.newInstance())
                            tem.each { k2, v2 ->    //domain ,[creater,parent.....]
                                def listtem2 = result.get(k2)
                                v2.each { vv2 ->
                                    def newName = "${p}.${vv}.${vv2}" //属变为 比如 job.name
                                    listtem2.add(newName)
                                }
                                if (map?.jici_used >= 4) {
                                    if (k2 == 'domain') { //对 doamin 再次级联的属性分析
                                        v2.each { vv3 ->     //creater
                                            def newClas3 = new DefaultGrailsDomainClass(newClas2).getPropertyByName(vv3).referencedPropertyType //StaffMember
                                            tem = getProsOne(newClas3.newInstance())
                                            tem.each { k3, v3 ->    //domain ,[creater,parent.....]
                                                def listtem3 = result.get(k3)
                                                v3.each { vv4 ->
                                                    def newName = "${p}.${vv}.${vv3}.${vv4}" //属变为 比如 job.name
                                                    listtem2.add(newName)
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return result
    }
    /**作用: 通用的综合查询 方法
     * 能各个属性查询,对于string 类型的是模糊查询,时间的可以按时间段查询,其他类型的按严格匹配查询
     * 参数: 1.实体中的各个属性名称 ,对于类型为实体的属性 也是 属性名称或 属性.属性;
     *      2.对于时间段的查询 需要提供 params.blsj(属性名称) 外加 params.beginTime 或/和 params.endTime
     *      3.对 hasMany 属性的查询 也是 实体属性.属性     ,对于  hasMany 的属性要是实体的首字母缩写,不然无法查询
     * 使用: 在control中:
     *      def domain = controllerName[0].toUpperCase() + controllerName[1..controllerName.length() - 1]
     def Instance = grailsApplication.classLoader.loadClass('fundSupervision.' + domain)
     def result = utilsService.commonlist(Instance, params)
     render result
     缺点: 没有 in  和or方法
     要求:如想按单位查询,各个实体中 有department属性 ,没有department属性的实体 不能传递  selfDep 或  includesub 参数
     allowStatus 格式为 'new'   或 'new','submit' (带''的字符串)   params.dateFormat 不传时默认查询年月

     2013-11-16 add
     if (utilsService.validString(params.beginTime) || utilsService.validString(params.endTime))
     params.accountDate = "yyyy-mm-dd"       //据到账日期查询    HH24:mi:ss
     params.jici_used=3    // 控制查询级次
     2014-03-03 add
     params.RETURNLIST=true //返回数组list ,调用的方法自己处理查询出来的结果的展示
     params.ONLYSQL=true //只返回sql

     params << ["shbm.id": utilsService.currentUser?.department?.id]
     params << ["shbm.idStringMatch": "0"]  // 全字匹配
     * @param Instance
     * @param params
     * @return
     */
    def springSecurityService

    def commonlist(Instance, params, Addsql = '', orderSql = '') {
        params.remove('_dc')
        def instance = firstXiaoXie(Instance.getSimpleName())
        def InstanceName = Instance.getSimpleName()
        def map = getPros(Instance.newInstance(), params)
        def parammap = [:]
//        log.debug(map)
        //  2013-11-16   add ----begin   用于 去掉treeCombo中 默认的name
        params.each { k, v ->
            if (!k?.toString().contains('ext')) {
                if (!k.toString().endsWith('Format') && !k.toString().endsWith('StringMatch')) {
                    //判定某个字段的格式化方式 不放入
                    parammap.put(k, v)
                }
            }
        }
        //  2013-11-16   add ----end
        parammap.remove('action')
        parammap.remove('controller')
        parammap.remove('selfDep')
        parammap.remove('includesub')
        parammap.remove('inchildDep')
        parammap.remove('inchildDepstr')
        parammap.remove('inchildDepidstr')
        parammap.remove('includesubmrstr')
        parammap.remove('includemr')
        parammap.remove('includemrdept')
        parammap.remove('allowStatus')
        parammap.remove('dateFormat')
        parammap.remove('beginTime')
        parammap.remove('endTime')
        parammap.remove('order')
        parammap.remove('sort')
        parammap.remove('max')
        parammap.remove('offset')

        parammap.remove('limit')
        parammap.remove('start')
        parammap.remove('jici_used')
        parammap.remove('RETURNLIST')
        parammap.remove('RETURNSQL')
        parammap.remove('ONLYSQL')

        parammap.remove('includeSubBudget')
        parammap.remove('StringMatch')
        parammap.remove('budgetSubjectSX')
        parammap.remove('inchildDepByDept')
        parammap.remove('statusZd')


        if (parammap.status == 'all') parammap.remove('status')
        def sql = " from ${InstanceName}  ${instance}"         //     select ${instance}
        if (params.needHasMany == 'true')
            map.hasMany.each {
                def bm = it.toString()//别名
                if (bm.contains('.')) bm = bm.replaceAll('.', '')
                sql += " left outer join   ${instance}.${it}  ${bm} "      //fetch
            }
        sql += "  where 1=1"
        parammap.each { k, v ->
//            log.debug(k+"   "+v)
            if (v.toString().startsWith('[') || v.toString()?.trim() == "") return         //xianjin.department  会产生  ["xianjin.department":"19", "xianjin":["department":"19"], "action":"test", "controller":"qthbzj"]     ,要去掉    "xianjin":["department":"19"]
            if (map.string.findAll { it.toString() == k.toString() }) {
                def matchModel = '3'
                if (validString(params["${k + "StringMatch".toString()}".toString()]))
                    matchModel = params["${k + "StringMatch".toString()}".toString()]
                if (matchModel == '1') {//1 前  2 后  3 全
                    sql += "  and ${instance}.${k} like '%${v}'"
                } else if (matchModel == '2') {
                    sql += "  and ${instance}.${k} like '${v}%'"
                } else if (matchModel == '3') {
                    sql += "  and ${instance}.${k} like '%${v}%'"
                } else if (matchModel == '0') {
                    sql += "  and ${instance}.${k} = '${v}'"
                }

            } else if (map.date.findAll { it.toString() == k.toString() }) {
                def f = 'yyyy-mm-dd'
                if (v != 'null') f = v
                if (validString(params.beginTime))
                    sql += "  and ${instance}.${k}>= to_date('" + params.beginTime + "','${f}')"      //oracle 专用
                if (validString(params.endTime))
                    sql += "  and ${instance}.${k}<=to_date('" + params.endTime + "','${f}')"       //oracle 专用
                if (!validString(params.beginTime) && !validString(params.endTime) && validString(v) && v != 'null') {
                    def format = params.dateFormat
                    if (!validString(format)) format = "yyyy-MM"
                    if (validString(params["${k + "Format".toString()}".toString()]))
                        format = params["${k + "Format".toString()}".toString()]

                    def dv = strToDate(v)
                    if (format.contains('yyyy')) sql += "  and year(${instance}.${k})=" + dv.format('yyyy').toInteger()
                    if (format.contains('MM')) sql += "  and month(${instance}.${k})=" + dv.format('MM').toInteger()
                    if (format.contains('dd')) sql += "  and day(${instance}.${k})=" + dv.format('dd').toInteger()
                    if (format.contains('HH')) sql += "  and hour(${instance}.${k})=" + dv.format('HH').toInteger()
                }
            } else if (map.boolean.findAll { it.toString() == k.toString() }) {
                sql += " and ${instance}.${k}=" + Boolean.valueOf(v?.toString())
            } else if (map.long.findAll { it.toString() == k.toString() }) {
                sql += " and ${instance}.${k}=" + Long.valueOf(v?.toString())
            } else if (map.int.findAll { it.toString() == k.toString() }) {
                sql += " and ${instance}.${k}=" + Integer.valueOf(v?.toString())
            } else if (map.float.findAll { it.toString() == k.toString() }) {
                sql += " and ${instance}.${k}=" + Float.valueOf(v?.toString())
            } else if (map.double.findAll { it.toString() == k.toString() }) {
                sql += " and ${instance}.${k}=" + Double.valueOf(v?.toString())
            } else if (map.domain.findAll { it.toString() == k.toString() }) {
                sql += " and ${instance}.${k}.id=${v}"
            } else if (k.toString()?.contains('.')) {
                def array = k.split('\\.')
                log.debug(k + "  " + array.toString())
                if (array.size() > 0) {
                    if (map.hasMany.findAll { it.toString() == array[0].toString() }) {
                        // 2014-10-12  fang  update   as Class  有误,应该在 map.hasMany 中指明 Class  需要大改动
                        def InstanceMany = firstDaXie(array[0]) as Class
                        def manyPro = getClassUnPersistentProperties(InstanceMany)
                        if (v.toString().startsWith('[') || v.toString()?.trim() == "") return
                        //xianjin.department  会产生  ["xianjin.department":"19", "xianjin":["department":"19"], "action":"test", "controller":"qthbzj"]     ,要去掉    "xianjin":["department":"19"]
                        if (manyPro.string.findAll { it.toString() == k.toString() }) {


                            def matchModel = '3'
                            if (validString(params["${k + "StringMatch".toString()}".toString()]))
                                matchModel = params["${k + "StringMatch".toString()}".toString()]
                            if (matchModel == '1') {//1 前  2 后  3 全
                                sql += "  and ${array[0]}.${k} like '%${v}'"
                            } else if (matchModel == '2') {
                                sql += "  and ${array[0]}.${k} like '${v}%'"
                            } else if (matchModel == '3') {
                                sql += "  and ${array[0]}.${k} like '%${v}%'"
                            } else if (matchModel == '0') {
                                sql += "  and ${instance}.${k} = '${v}'"
                            }

                        } else if (manyPro.date.findAll { it.toString() == k.toString() }) {
                            def format = params.dateFormat
                            if (!validString(format)) format = "yyyy-MM"
                            def dv = strToDate(v)
                            if (format.contains('yyyy')) sql += "  and year(${array[0]}.${k})=" + dv.format('yyyy').toInteger()
                            if (format.contains('MM')) sql += "  and month(${array[0]}.${k})=" + dv.format('MM').toInteger()
                            if (format.contains('dd')) sql += "  and day(${array[0]}.${k})=" + dv.format('dd').toInteger()
                            if (format.contains('HH')) sql += "  and hour(${array[0]}.${k})=" + dv.format('HH').toInteger()
                        } else if (manyPro.boolean.findAll { it.toString() == k.toString() }) {
                            sql += " and ${array[0]}.${k}=" + Boolean.valueOf(v?.toString())
                        } else if (manyPro.long.findAll { it.toString() == k.toString() }) {
                            sql += " and ${array[0]}.${k}=" + Long.valueOf(v?.toString())
                        } else if (manyPro.int.findAll { it.toString() == k.toString() }) {
                            sql += " and ${array[0]}.${k}=" + Integer.valueOf(v?.toString())
                        } else if (map.float.findAll { it.toString() == k.toString() }) {
                            sql += " and ${array[0]}.${k}=" + Float.valueOf(v?.toString())
                        } else if (manyPro.double.findAll { it.toString() == k.toString() }) {
                            sql += " and ${array[0]}.${k}=" + Double.valueOf(v?.toString())
                        } else if (manyPro.domain.findAll { it.toString() == k.toString() }) {
                            sql += " and ${array[0]}.${k}.id=${v}"
                        }
                    } else {
                        def matchModel = '3'
                        if (validString(params["${k + "StringMatch".toString()}".toString()]))
                            matchModel = params["${k + "StringMatch".toString()}".toString()]
                        if (matchModel == '1') {//1 前  2 后  3 全
                            sql += "  and ${k} like '%${v}'"
                        } else if (matchModel == '2') {
                            sql += "  and ${k} like '${v}%'"
                        } else if (matchModel == '3') {
                            sql += "  and ${k} like '%${v}%'"
                        } else if (matchModel == '0') {
                            sql += "  and ${k} = '${v}'"
                        }
                    }

                } else {
                    def matchModel = '3'
                    if (validString(params["${k + "StringMatch".toString()}".toString()]))
                        matchModel = params["${k + "StringMatch".toString()}".toString()]
                    if (matchModel == '1') {//1 前  2 后  3 全
                        sql += "  and ${instance}.${k} like '%${v}'"
                    } else if (matchModel == '2') {
                        sql += "  and ${instance}.${k} like '${v}%'"
                    } else if (matchModel == '3') {
                        sql += "  and ${instance}.${k} like '%${v}%'"
                    } else if (matchModel == '0') {
                        sql += "  and ${instance}.${k} = '${v}'"
                    }

                }
            } else {
                log.debug("-->" + k)
                def matchModel = '3'
                if (validString(params["${k + "StringMatch".toString()}".toString()]))
                    matchModel = params["${k + "StringMatch".toString()}".toString()]
                if (matchModel == '1') {//1 前  2 后  3 全
                    sql += "  and ${instance}.${k} like '%${v}'"
                } else if (matchModel == '2') {
                    sql += "  and ${instance}.${k} like '${v}%'"
                } else if (matchModel == '3') {
                    sql += "  and ${instance}.${k} like '%${v}%'"
                } else if (matchModel == '0') {
                    sql += "  and ${instance}.${k} = '${v}'"
                }

            }
        }
        //只能查看本单位的
        if (params.selfDep == 'true') {
            sql += "  and ${instance}.department.id=" + springSecurityService.currentUser?.department?.id
        }
        //可以查看本单位和下级单位的  xcc添加
        if (params.inchildDep == 'true') {
            def deptbsstr = combolistByDeptstr();
            if (params.inchildDepidstr) deptbsstr = params.inchildDepidstr
            sql += "  and ${instance}." + params.inchildDepstr + ".id  in(" + deptbsstr + ")"
            log.info(sql + "  inchildDep:" + params.inchildDep)
        }
        //可以查看本单位和下级单位的  按单位 查询
        if (params.inchildDepByDept == 'true') {
            sql += "  and ${instance}." + params.inchildDepstr + ".code  like '" + springSecurityService.currentUser?.department?.code + "%' "
            log.info(sql + "  inchildDep:" + params.inchildDep)
        }
        //可以查看本单位和下级单位的  xcc添加
        if (params.include == 'true') {
            def deptbsstr = combolistByDeptstr();
            if (params.inchildDepidstr) deptbsstr = params.inchildDepidstr
            sql += "  and ${instance}." + params.inchildDepstr + ".id  in(" + deptbsstr + ")"
            log.info(sql + "  inchildDep:" + params.inchildDep)
        }

        //可以查看本单位和下级单位的   按照某个单位
        if (params.includemr == 'true') {

            def list = params.includemrdept?.includechildlist().id
            list << params.includemrdept?.id
            sql += "  and ${instance}." + params.includesubmrstr + ".id  in(" + list.flatten().join(',') + ")"
        }
        if (validString(params.allowStatus)) {
            if (params.statusZd) {
                sql += " and  ${instance}.${params.statusZd} in (${params.allowStatus})"
            } else
                sql += " and  ${instance}.status in (${params.allowStatus})"
        }
        sql += Addsql
        //排序
        if (orderSql != '') {
            sql += orderSql
        } else {
            if (!validString(params.sort)) params.sort = "id"
            if (!validString(params.order)) params.order = 'ASC'
            sql += "  order by ${instance}.${params.sort}  ${params.order}"
        }
        log.info(sql + "  max:" + params.max + "  offset:" + params.offset)
        def list = []
        def result = [:]
        if (validString(params.ONLYSQL)) {     //返回Sql
            result.sqlstr = "select ${instance}" + sql
        } else {
            if (validString(params.max) && validString(params.offset)) {
                list = Instance.executeQuery("select ${instance}" + sql, [max: params.max as int, offset: params.offset as int])
            } else {
                list = Instance.executeQuery("select ${instance}" + sql)
            }

//        if (params.needHasMany == 'true')
//            result.total = Instance.executeQuery("select ${instance}" + sql).size()
//        else
            result.total = Instance.executeQuery("select count(distinct ${instance})" + sql)[0]
            if (!validString(params.RETURNLIST)) {
                result.gridroot = Instance.newInstance().buildDomainList(list)
            } else {     // 返回list,到调用方法中是处理显示
                result.list = list
            }
            if (validString(params.RETURNSQL)) {
                result.sqlstr = "select ${instance}" + sql
            }
        }
        result

    }
    /**
     *
     * @param Instance Class
     * @param params
     * @param headhql from ${instance.class.name} where 1=1
     * @return sql
     */
    def commhql(Instance, params, headhql) {
        params.remove('_dc')
        def instance = Instance.newInstance()
        def map = getPros(instance, params)
        def parammap = [:] + params
        log.debug(params)
        parammap.remove('action')
        parammap.remove('controller')
        parammap.remove('selfDep')
        parammap.remove('includesub')
        parammap.remove('allowStatus')
        parammap.remove('order')
        parammap.remove('sort')
        parammap.remove('limit')
        parammap.remove('max')
        parammap.remove('offset')
        if (parammap.status == 'all') parammap.remove('status')
        def sql = headhql
        parammap.each { k, v ->
//            log.debug(k+"  "+v)
            if (v.toString().startsWith('[') || v.toString()?.trim() == "") return         //xianjin.department  会产生  ["xianjin.department":"19", "xianjin":["department":"19"], "action":"test", "controller":"qthbzj"]     ,要去掉    "xianjin":["department":"19"]
            if (map.string.findAll { it.toString() == k.toString() }) {
                sql += "  and ${k} like '%${v}%'"
            } else if (map.date.findAll { it.toString() == k.toString() }) {
                if (validString(params.beginTime))
                    sql += "  and ${k}>='" + params.beginTime + "'"
                if (validString(params.endTime))
                    sql += "  and ${k}<='" + params.endTime + "'"
                if (!validString(params.beginTime) && !validString(params.endTime)) {
                    def format = params.dateFormat
                    if (!validString(format)) format = "yyyy-MM"
                    def dv = strToDate(v)
                    if (format.contains('yyyy')) sql += "  and year(${k})=" + dv.format('yyyy').toInteger()
                    if (format.contains('MM')) sql += "  and month(${k})=" + dv.format('MM').toInteger()
                }
            } else if (map.equal.findAll { it.toString() == k.toString() }) {
                sql += " and ${k}=${v}"
            } else {
                sql += "  and ${k} like '%${v}%'"
            }
        }
        //排序
        if (!validString(params.sort)) params.sort = 'id'
        if (!validString(params.order)) params.order = 'ASC'
        sql += "  order by ${params.sort}  ${params.order}"
        return sql
    }

    def objtoBoolean(a) {
        def result = null
        if (isNumber(a)) result = (a as int).asBoolean()
        else {
            result = Boolean.valueOf(a?.toString())
        }
    }

    /**
     * 使用方法  在Control中:
      def instance = new Instance()
     if (utilsService.validString(params.id))  instance=Instance.get(params.id)
     utilsService.changeParams(instance, params)
     utilsService.changeParams(instance, params)
     bindData(instance,params)    //或者  instance.properties=params
     if (!instance.save()) {instance.errors.each {log.debug(it)}}* @param instance
     * @param params 实体中的各属性
     * @return
     */
    def changeParams(instance, params) {
        def mapt = [jici_used: 0]
        def map = getPros(instance, mapt)
//        log.debug(map)
        def p2 = [:]
        p2.putAll(params)
        p2.remove('dateCreated')
        p2.remove('lastUpdated')
        if (!validString(params.format)) params.format = "yyyy-MM-dd HH:mm:ss"
        p2.each { k, v ->
//            log.debug( k+"  "+v+"  "+validString(v))
            if (validString(v?.toString()?.trim())) {
//                log.debug(k + "  " + v + "  " + validString(v+"  "+map.boolean.contains(k).toString()))
                if (map.string.contains(k)) params."${k}" = v
                else if (map.long.contains(k) && isNumber(v)) params."${k}" = Long.valueOf(v)
                else if (map.date.contains(k)) params."${k}" = strToDate(v)//Date.parse(params.format, v)
                else if (map.double.contains(k)) params."${k}" = BigDecimal.valueOf(Double.valueOf(v))
                else if (map.boolean.contains(k)) params."${k}" = objtoBoolean(v)
                else if (map.domain.contains(k)) {
//                    log.debug("remove-->"+k)
                    params.remove(k)
                    if (v?.toString() != "0")
                        params."${k}" = v
                } else if (map.hasMany.contains(k)) { //对于hasMany 转为数组
                    if (v?.toString()?.contains('[') && v?.toString()?.contains(']')) {
                    } else params."${k}" = v?.toString()?.split(',')
                }
            } else {
//                log.debug("remove2-->"+k)
                params.remove(k)
            }
            if (params.DELETEOTHER == true) {          //据标志位是否删除 实体外的参数
                if (!map.all.contains(k)) {
//                    log.debug("remove3 " + k)
                    params.remove(k)
                }
            }
        }
        params.remove('format')
        params.remove('DELETEOTHER')
        params
    }

    /**        dics 根节点,list 范围   ,check为true 带复选框
     *    需要实体 有 buildDomain 方法例如:
     *      def buildDomain() {def b = [:] + this.properties
     b.remove('statusMap')
     b.remove('fromTypeMap')
     b.remove('descendants')
     b = utilsService.truncProp(b) { amap ->
     amap << ['fromType': fromTypeMap.get(fromType)]
     amap << ['status': statusMap.get(status)]}b}*/

    def treelist(dics, list, checklist = null) {
//        def dics = Account.findAllByParentIsNull()     //.find{} 可以追加条件
//        def list = Account.findAll().sort() { b, a -> b.id <=> a.id }
        log.info("树的选择范围${list.size()}个")
        def result = []
        dics.each { dic ->
            def node = [:]
            node.putAll(dic.buildDomain())
            node.leaf = true
            if (dic in checklist) node.checked = false
            digui(node, dic, list, checklist)
            result << node
        }
        result
    }

    def digui(parentNode, department, list, checklist) {
        if (!department) return
        list.findAll { it.parent == department }.sort() { b, a -> a.id <=> b.id }.each { dept ->
            if (dept) {
                def node = [:]
                node.putAll(dept.buildDomain())
                node.leaf = true
                if (dept in checklist) node.checked = false
                if (parentNode.leaf) {
                    parentNode.leaf = false
                    parentNode.expanded = false
                }
                digui(node, dept, list, checklist)
                if (parentNode.children == null)
                    parentNode.children = [node]
                else
                    parentNode.children << node
            }
        }
    }
    //分级显示 懒加载
    def treelistfj(dics, list, checklist = null) {
        //        def dics = Account.findAllByParentIsNull()     //.find{} 可以追加条件
        //        def list = Account.findAll().sort() { b, a -> b.id <=> a.id }
        log.info("树的选择范围${list.size()}个")
        def result = []
        dics.each { dic ->
            def node = [:]
            def map = dic.buildDomain()
            map.remove('children')
            map.remove('childrenName')
            node.putAll(map)
            if (dic.children) {
            } else node.leaf = true
            if (dic in checklist) node.checked = false
            digui1(node, dic, list, checklist)
            if (dic in list)
                result << node

        }
        result
    }

    //已经用到
    def digui1(parentNode, department, list, checklist) {
        if (!department) return
        list.findAll { it.parent == department }.sort() { b, a -> a.id <=> b.id }.each { dept ->
            if (dept) {
                def node = [:]
                def map = dept.buildDomain()
                map.remove('children')
                map.remove('childrenName')
                node.putAll(map)
                if (dept.children) {
                } else node.leaf = true
                if (dept in checklist) node.checked = false
                if (parentNode.leaf) {
                    parentNode.leaf = false
                    parentNode.expanded = false
                }
                digui(node, dept, list, checklist)
                if (parentNode.children == null)
                    parentNode.children = [node]
                else
                    parentNode.children << node
            }
        }
    }
    ////////对于像部门有上下级关系的,下面的方法适用  -------begin
    //得到所有最顶层的父节点
    def getTopParents(department) {
        if (!department.parent)
            return department
        return getAllParents(department).find { it.parent == null }
    }
    //得到所有父亲
    def getAllParents(department) {
        def list = []
        if (department?.parent) {
            list.add(department.parent)
            list.add(getAllParents(department.parent))

        }
        return list.flatten()
    }
    //得到直接下级
    def getChildren(Class className, department) {
        def list = className.findAllByParent(department)
        list
    }
    //fang add 2012-5-9 查询出所有的父权限 返回 权限list     .flatten()
    // [system.Authority : 4, [system.Authority : 3, [system.Authority : 2, system.Authority : 1]]]
    def parentList(authority) {
        if (authority.parent == null) return [authority]
        else {
            return [authority] << parentList(authority.parent)
        }
    }
    //fang add 2012-5-9 得到所有的孩子节点 (包括直接和间接的)
    //返回:[system.Authority : 1, system.Authority : 2, system.Authority : 3, system.Authority : 4]
    def childrenList(authority) {
        if (authority.children == null) return [authority]
        else {
            def result = [authority]
            authority.children.each {
//                log.debug("it-->" + it)
                result.addAll(childrenList(it))
            }
            return result
        }
    }
    //   -------end
    //ceui
//    def synchronized saveAttavtment() {
////        Attachment attachment = new Attachment()
//        Attachment attachment = Attachment.get(13287.toLong())
//        attachment.fileName = "fileName.txt"
//        attachment.suffix = "txt"
//        attachment.fromId = "1"
//        attachment.fromDomain = "YssbInit"
//        attachment.remark = new Date().format("yyyyMMddHHmmssSS")
//        attachment.creater = springSecurityService.currentUser
//        save(attachment)
//
//
//    }

    def save(domain) {
        domain?.clearErrors()
        if (!domain.save()) {
            domain.errors.each {
                log.error(it)
            }
            return null
        } else return domain
    }
    //字符串 首字母小写
    def firstXiaoXie(String str) {
        char[] chars = new char[1];
        chars[0] = str.charAt(0);
        String temp = new String(chars);
        if (chars[0] >= 'A' && chars[0] <= 'Z') {
            return (str.replaceFirst(temp, temp.toLowerCase()));
        } else
            return str

    } //字符串 首字母大写
    def firstDaXie(String str) {
        char[] chars = new char[1];
        chars[0] = str.charAt(0);
        String temp = new String(chars);
        if (chars[0] >= 'a' && chars[0] <= 'z') {
            return (str.replaceFirst(temp, temp.toUpperCase()));
        } else
            return str

    }

    // 分割 1,2,3 转为 '1','2','3'
    def splitstatus(String status) {
        def s = status.split(',')
        def ss = ""
        s.each {
//              log.debug("status  "+it)
            ss += "'" + it + "',"
        }
        if (s.size() > 0) ss = ss[0..ss.size() - 2]
        return ss
    }
    /**
     * @param day1 开始时间
     * @param day2 截止时间
     * @param n 多少个单位
     * @param type 单位: years months   weeks  days hours   minutes  seconds   milliseconds
     * @return [reslut , lastDay]  返回结果[reslut,lastDay] 是 时间段内有多少个间隔(n*type) 即:  day1+result*间隔=lastDay>=day2
     * 例如: type为天 day1 为第0天,day2 即为 第result 天
     *       type为周  day1 为第0周的某一天    day2 为第j周的某一天       lastday 为 第j周的最后一天
     */
    def jiange(Date day1, Date day2, n = 1, type = 'days') {
        //years months ,weeks  days hours   minutes  seconds   milliseconds
        def j = 0, lastday, beginday
        use(TimeCategory) {
            for (j = 0; (day1 + ((n * j)."${type}")) <= (day2); j++) {
//                log.debug(j)
            }
            j = j - 1
            lastday = day1 + ((n * j + n)."${type}")
            beginday = day1 + ((n * j)."${type}")
            // beginday=nextNday(day1,1)             //时间开始时间=上一个结束时间+1
        }
        return [j, lastday, beginday]
    }
    /**
     * 计算时间段的差值
     * */
    def getBetweenTime(Date d2, Date d1) {
        long l = d1.getTime() - d2.getTime();
        long day = l / (24 * 60 * 60 * 1000);
        long hour = (l / (60 * 60 * 1000) - day * 24);
        long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60);
        long s = (l / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
        log.debug("相差${day} 天 ${hour}小时  ${min}分 ${s}秒")
        return [day: day, hour: hour, min: min, s: s]
    }
    /* 获取流程流水号 通过当前时间+随机数*1000
    * @return
    * @create 2013-03-17 17:00 Changshui.Feng
    */

    def getFlowId() {
        // 取当前时间
        long currentTime = System.currentTimeMillis();
        int randD = (int) (Math.random() * 1000);
        String flowId_temp = String.valueOf(currentTime) + randD;

        long flowId = Long.valueOf(flowId_temp);
        return flowId;
    }

    def Map<String, Object> parseJSON2Map(String jsonStr) {
        Map<String, Object> map = new HashMap<String, Object>();
        //最外层解析

        //           JSONObject json = JSONObject.fromObject(jsonStr);           java 中使用
        JSONObject json = new JSONObject(jsonStr);
        for (Object k : json.keySet()) {
            Object v = json.get(k);
            //如果内层还是数组的话，继续解析
            if (v instanceof JSONArray) {
                List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
                Iterator<JSONObject> it = ((JSONArray) v).iterator();
                while (it.hasNext()) {
                    JSONObject json2 = it.next();
                    list.add(parseJSON2Map(json2.toString()));
                }
                map.put(k.toString(), list);
            } else {
                map.put(k.toString(), v);
            }
        }
        return map;
    }

    //  数字的金额分成数组形式的字符串   由亿到分
    def jineToString(def jine) {
        def hjje = (jine + "").split("\\.")
        def hjjelist = ["0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"]
        for (int i = 0; i < hjje[0].length(); i++) {
            String perchar = hjje[0].charAt(i);
            int j = hjje[0].length() - i - 1;
            if (j == 0)
                hjjelist[8] = perchar
            if (j == 1 && perchar != 0)
                hjjelist[7] = perchar
            if (j == 2 && perchar != 0)
                hjjelist[6] = perchar
            if (j == 3 && perchar != 0)
                hjjelist[5] = perchar
            if (j == 4 && perchar != 0)
                hjjelist[4] = perchar
            if (j == 5 && perchar != 0)
                hjjelist[3] = perchar
            if (j == 6 && perchar != 0)
                hjjelist[2] = perchar
            if (j == 7 && perchar != 0)
                hjjelist[1] = perchar
            if (j == 8 && perchar != 0)
                hjjelist[0] = perchar
        }
        if ((jine + "").indexOf(".") != -1) {
            if (hjje[1].length() > 2) {
                hjje[1] = hjje[1].substring(0, 2);
            }
            for (int m = 0; m < hjje[1].length(); m++) {
                String perchar1 = hjje[1].charAt(m);
                if (m == 0 && perchar1 != 0)
                    hjjelist[9] = perchar1
                if (m == 1 && perchar1 != 0)
                    hjjelist[10] = perchar1
            }
        }
        return hjjelist
    }

    StaffMember getCurrentUser() {
        def result = springSecurityService.currentUser
        if (result == null || result?.username == null) {
            result = StaffMember.findByUsername(session.username)
        }
        if (result == null || result?.username == null) {
            result = StaffMember.findByUsername(springSecurityService.authentication.name)
        }
        return result
    }

    /**
     *
     * @param str 传入的code
     * @param length 要求code长度
     * @param lr 两个值 l r 表示左补齐 右补齐
     * @param chart 补齐的字符
     * @return 格式化后的code
     */
    def getFormatCode(str, length, lr, chart) {
        while (true) {
            if (str.length() < length) {
                if (lr == "l") {
                    str = chart + str
                } else {
                    str = str + chart
                }
            } else {
                break
            }
        }
        return str
    }
    // 导入时用到的code转码,对于针对数字型的编码的处理
    def changCode(code) {
        def result = ""
        if (isNumber(code)) {
            def str = code.toString()
            if ((code as BigDecimal).toLong() != 0) {
                String tem = str
                def beStr = ""
                while (tem.startsWith('0')) {
                    if (tem.size() > 0) {
                        beStr += "0"
                        tem = tem[1..tem.size() - 1]
                    } else break
                }
                result = beStr + (tem as BigDecimal).toLong().toString()
            } else {
                result = code.toString()
            }
        } else result = code.toString().trim()
        return result
    }

    def pageList(results, offset, max) {
        def last = offset + max - 1;
        if (results.size() <= offset + max) {
            last = results.size() - 1
        }
        if (last < 0)
            return []
        else
            return results[offset..last]
    }

    /**
     * <b>function:</b> 处理oracle sql 语句in子句中（where id in (1, 2, ..., 1000, 1001)），
     * 如果子句中超过1000项就会报错。
     * 这主要是oracle考虑性能问题做的限制。
     * 如果要解决次问题，可以用 where id (1, 2, ..., 1000) or id (1001, ...)
     * @author hoojo
     * @createDate 2012-8-31 下午02:36:03
     * @param ids in语句中的集合对象
     * @param count in语句中出现的条件个数
     * @param field in语句对应的数据库查询字段
     * @return 返回 field in (...) or field in (...) 字符串
     */
    private String getOracleSQLIn(List<?> ids, int count, String field) {
        count = Math.min(count, 1000);
        int len = ids.size();
        int size = len % count;
        if (size == 0) {
            size = len / count;
        } else {
            size = (len / count) + 1;
        }
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < size; i++) {
            int fromIndex = i * count;
            int toIndex = Math.min(fromIndex + count, len);
            //System.out.println(ids.subList(fromIndex, toIndex));
            String productId = StringUtils.defaultIfEmpty(StringUtils.join(ids.subList(fromIndex, toIndex), "','"), "");
            if (i != 0) {
                builder.append(" or ");
            }
            builder.append(field).append(" in ('").append(productId).append("')");
        }

        return StringUtils.defaultIfEmpty(builder.toString(), field + " in ('')");
    }

    private String getOracleSQLNotIn(List<?> ids, int count, String field) {
        count = Math.min(count, 1000);
        int len = ids.size();
        int size = len % count;
        if (size == 0) {
            size = len / count;
        } else {
            size = (len / count) + 1;
        }
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < size; i++) {
            int fromIndex = i * count;
            int toIndex = Math.min(fromIndex + count, len);
            //System.out.println(ids.subList(fromIndex, toIndex));
            String productId = StringUtils.defaultIfEmpty(StringUtils.join(ids.subList(fromIndex, toIndex), "','"), "");
            if (i != 0) {
                builder.append(" or ");
            }
            builder.append(field).append(" not in ('").append(productId).append("')");
        }

        return StringUtils.defaultIfEmpty(builder.toString(), field + " not in ('')");
    }
    //针对前台 传递过来的数组 类型的 参数 转为list
    def strtoList(str) {
        def list = [];
        if (str?.getClass()?.getName() == "[Ljava.lang.String") { //防止一个id时被拆分
            str.each {
                list << it
            }
        } else list.addAll(str)
        list.findAll { it != null }
    }

    /*
 判断实体中是否存在字段相同的实体,存在返回 存在实体的List
 默认返回 null
参数:map.Domain  实体Class , map.id  实体id可以为空 ,map.zdName  实体字段名 ,map.zdValue 字段对应的值
  */

    def zdExitInDoamin(map) {
        if (!validString(map.Domain)) throw new IllegalArgumentException("参数Domain有误")
        else if (!validString(map.zdName)) throw new IllegalArgumentException("参数zdName有误")
        else if (!validString(map.zdValue)) throw new IllegalArgumentException("参数zdValue有误")
        def Instance = map.Domain
        def result = []
        if (validString(map.id)) {
            result = Instance.findAll("from ${Instance.getSimpleName()} where  ${map.zdName}=:zd and id!=:id", [zd: map.zdValue, id: map.id as long])
        } else {
            result = Instance.findAll("from ${Instance.getSimpleName()} where  ${map.zdName}=:zd", [zd: map.zdValue])
        }
        if (result.size() == 0) result = null
        result
    }
    //redmine 1670 changfenghua 20140811 add start
    /**
     * 给部门添加级次
     * @return
     */
    def getJiCi(department) {
        if (!department.parent) {
            return 1;
        } else {
            return getJiCi(department.parent) + 1
        }
    }

    def getDepartmentWithJiCi() {
        def hql = "from Department where dr=0";
        def departmentList = Department.executeQuery(hql);
        def departmentWithJiCiList = []
        departmentList.each {
            departmentWithJiCiList << [((it.id).toString()): getJiCi(it)]
        }
        return departmentWithJiCiList
    }


    // 当前操作人所在公司
    def getCurGs() {
//        Department.findAll("from  Department  where  code like :code and departmentType.name='公司'", [code: currentUser.department?.code + '%'])?.find {
//            true
//        }
        def gs=getGsList(currentUser.department)?.find { true }
        if(gs==null){
            gs=getJtList(currentUser.department)?.find { true }
        }
        return gs
    }

    def getGsList(Department department) {
        parentList(department).flatten().findAll { it.departmentType?.name == '公司' }.unique()
    }
    def getJtList(Department department) {
        parentList(department).flatten().findAll { it.departmentType?.name == '集团' }.unique()
    }

    /**
     * 获取当年的第一天
     * @param year
     * @return
     */
    public static Date getCurrYearFirst(){
        Calendar currCal=Calendar.getInstance();
        int currentYear = currCal.get(Calendar.YEAR);
        return getYearFirst(currentYear);
    }
    /**
     * 获取某年第一天日期
     * @param year 年份
     * @return Date
     */
    public static Date getYearFirst(int year){
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        Date currYearFirst = calendar.getTime();
        return currYearFirst;
    }
    def getGsByDepartment(Department department){
        def gs=parentList(department).flatten().findAll { it.departmentType.name == '公司' }.unique();
        if(gs!=null&&gs.size()>0){
            return gs[0];
        }
        gs= parentList(department).flatten().findAll { it.departmentType.name == '集团' }.unique();
        return gs[0];
    }

  //查询某个流程当前处于什么么环节

    def getzxhj(def piid){
        def result=[];
        List temlist= historyService.createHistoricTaskInstanceQuery().processInstanceId(piid).list()?:[]
        for(int i=0; i<temlist.size();i++){
            result <<temlist.get(i);
        }

       def zxhj= result.sort() { a, b -> b.startTime <=> a.startTime }[0]
        return zxhj.name?:''
    }

    //得到该htName所有非驳回 的环节实体的sql,用于拼接sql
    // 调用方法 "select  instance.id"+utilsService.getHtAllPiidSql(map)
    String getHtAllPiidSql(map) {
        def Domain = map.Domain
        def htname = map.htName
        def processName = map.processName
        def InstanceName = Domain.getSimpleName()
        def str = "  from  ${InstanceName} instance  where instance.htName='${htname}' and  instance.dateCreated>=(select max(dateCreated) from  ${InstanceName} where  htName=(select stepName  from  WindowConfig   where processName='${processName}' and  isStartTask=1)  and piid=instance.piid)"
        return str
    }
    //得到所有流程某个环节的最新流程环节 数据        ,最好改成视图,其他地方现在用的in 来拼接的sql,数据量上来后,会出现sql 过长的问题
    //  参数:[Domain:ClckdProcess,htName:'']
    // 返回:List<CommonTask>
    List<CommonTask> getHtAllPiid(map) {
        def Domain = map.Domain
        def htname = map.htName
        def piidlist = Domain.findAllByHtName(htname).groupBy { it.piid }
        // [1:["a", "b", "c"], 2:["ab", "bc"], 3:["abc"]]
        def list = []
        piidlist?.each { k, v ->       //List<CommonTask>
            def tem = v.sort { b, a -> a.dateCreated <=> b.dateCreated }.find { true }
            if (tem)
                list << tem
        }
        return list
    }
    /**
     * 接受解析
     */
    private jsjx(request) {
        def result = [:]
        if(request){
            // 读取请求内容
            BufferedReader br = new BufferedReader(new InputStreamReader(request?.getInputStream()));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br?.readLine()) != null) {
                sb.append(line);
            }
            // 将资料解码
            String reqBody = sb.toString();
            def js = URLDecoder.decode(reqBody, "utf-8");
            if (validString(js))
                result = net.sf.json.JSONObject.fromObject(js)
        }
        return result
    }

    ///
    /// 获得一个字符串的汉语拼音码
    ///   输入:"你好"
//    输出:NH
    /// name="strText">字符串
    /// 汉语拼音码,该字符串只包含大写的英文字母
    String GetChineseSpell(String strText) {
        return HanziToPinyin.GetChineseSpell(strText);
    }// GetChineseSpell

    String GetFirstPinyin(String strText) {
        return HanziToPinyin.GetFirstPinyin(strText);
    }// 获取首字的形状拼音字母
    String GetJsgjs(String name, String code){
        def str = GetChineseSpell(name)+GetFirstPinyin(name)?.toUpperCase()+GetFirstPinyin(name)?.toLowerCase()+code
        return str
    }
   static String getSysUrl(){
      def url=  getApplicationProStatic("app.url","application.properties","sharing")//org.springframework.core.io.support.PropertiesLoaderUtils.loadProperties(new org.springframework.core.io.ClassPathResource("application.properties")).getProperty('app.url')?.trim()
//      if (!url.endsWith("/")) url+="/"
        return url
    }
    String getJkUrl(){
        return  this.sysUrl+"/openInvoke/invoke"
    }

    def getAppName(){
        return  getApplicationPro("app.name","application.properties","index_xsy") //org.springframework.core.io.support.PropertiesLoaderUtils.loadProperties(new org.springframework.core.io.ClassPathResource("application.properties")).getProperty('app.name')?.trim()
    }
    String getPropertis(String str, fileName, xmmc) {
        def modelName =  grails.util.Environment.getCurrent().name.toUpperCase()
        InputStream fis;
        if (modelName == 'DEVELOPMENT') {
            fis = new FileInputStream("../${xmmc}/web-app/${fileName}");
        } else {
            def xmlu=this.PATHMAP.get(xmmc)
            def path=this.ROOT_PATH +xmlu+"/"+fileName
            log.debug(path)
            fis = new FileInputStream(path);
        }
        Properties prop = new Properties();
        prop.load(fis)
        def sx = prop.get(str)
        return sx
    }
    String getApplicationPro(String str, fileName, xmmc) {//  用于查询与  application.properties 同级的文件
//        def modelName =  grails.util.Environment.getCurrent().name.toUpperCase()
        InputStream fis;
        log.debug(this.ROOT_PATH)
        def modelName =  grails.util.Environment.getCurrent().name.toUpperCase()
        if (modelName == 'DEVELOPMENT') {
            fis = new FileInputStream("../${xmmc}/${fileName}");
        } else {
            if(this.ROOT_PATH.contains("web-app"))
            fis = new FileInputStream("./${fileName}");
            else{// tomcat 下面
                fis = new FileInputStream(this.ROOT_PATH+"WEB-INF\\classes\\${fileName}");
            }
        }
        Properties prop = new Properties();
        prop.load(fis)
        def sx = prop.get(str)
        return sx
    }
    static String getApplicationProStatic(String str, fileName, xmmc) {
        def modelName =  grails.util.Environment.getCurrent().name.toUpperCase()
        InputStream fis;
        if (modelName == 'DEVELOPMENT') {
            fis = new FileInputStream("../${xmmc}/${fileName}");
        } else {
            if(this.ROOT_PATH.contains("web-app"))
                fis = new FileInputStream("./${fileName}");
            else{// tomcat 下面
                fis = new FileInputStream(this.ROOT_PATH+"WEB-INF\\classes\\${fileName}");
            }
        }
        Properties prop = new Properties();
        prop.load(fis)
        def sx = prop.get(str)
        return sx
    }
}

